package org.jspar.place;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jspar.Partition;
import org.jspar.model.Module;
import org.jspar.model.Terminal;
import org.jspar.tile.ITileContent;

public class ModuleString implements ITileContent {

	private List<Module> modules;
	private int width, height;

	public ModuleString() {
		modules = new ArrayList<Module>();
		width = -1;
		height = -1;
	}
	
	public int length() { return modules.size(); }
	public int width() { return width; }
	public int height() { return height; }
	public void setSize(int w, int h) { width = w; height = h; }
	
	public void updateSize(int w, int h) {
		if (w > width) width = w;
		if (h > height) height = h;
	}
	
	public Module moduleAt(int i) {
		return (Module) modules.get(i);
	}

	public void add(Module module) {
		modules.add(0, module);
	}
	
	public List<Module> modules() {
		return modules;
	}

	public void mergeWith(ModuleString str) {
		for (int i = 0; i < str.length(); ++i) {
			if (! contains(str.moduleAt(i)))
				modules.add(str.moduleAt(i));
		}
	}

	public boolean contains(Module m) {
		return modules.contains(m);
	}

	public boolean isAnyPlaced() {
		for (Module module : modules) {
			if (module.hasFlag(Module.PLACED))
				return true;
		}
		return false;
	}

	public void resetTrace() {
		for (Module module : modules) {
			module.clearFlag(Module.SEEN | Module.PLACED);
		}
	}

	public void setFlagsFrom(int flags, int s) {
		for (int i = s; i < modules.size(); ++i) {
			modules.get(i).setFlag(flags);
		}
	}

	public void removeSystemTerminals() {
		Iterator<Module> i = modules.iterator();
		while(i.hasNext()) {
			Module module = i.next();
			if (module.type().isSystemTerminal())
				i.remove();
		}
	}
	
	public void move(int xoff, int yoff) {
		for (Module module : modules) {
			module.setPosition(module.x() + xoff, module.y() + yoff);
		}
	}

	public void fixupOffset(int xoff, int yoff) {
		width -= xoff;
		height -= yoff;
		for (Module module : modules) {
			module.setPosition(module.x() - xoff, module.y() - yoff);
		}
	}

	public void connectionsDo(Partition p, IOutsideConnectionEnumerator e) {
		for(Module imod : modules) {
			for(Terminal jterm : imod.terminals()) {
				for(Terminal kterm : jterm.net().terminals()) {
					Module m = kterm.module();
					if(imod != m
							&& m.hasFlag(Module.PLACED)
							&& m.partition() == p
							&& ! contains(m)) {
						e.terminalsDo(jterm, kterm);
					}
				}
			}
		}
	}

	public int countConnectionsTo(Partition p) {
		ConnectionCounter counter = new ConnectionCounter();
		connectionsDo(p, counter);
		return counter.count();
	}

	public SideSelector bestSide(Partition p, boolean useAveraging) {
		SideSelector selector = new SideSelector(useAveraging);
		connectionsDo(p, selector);
		selector.completeSelection();
		return selector;
	}
	
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append('[');
		for (int i = 0; i < modules.size(); ++i) {
			if (i != 0) buffer.append(' ');
			Module module = (Module) modules.get(i);
			buffer.append(module.name());
		}
		buffer.append(']');
		return buffer.toString();
	}
	
}
